#pragma once

#include <vector>
#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include "Sem.hpp"
#include "Mutex.hpp"
namespace RingBufferModule
{
    using namespace SemModel;
    using namespace LockMutex;
    template <typename T>
    class RingBuffer
    {
    public:
        RingBuffer(int cap) : _ring(cap), _cop(cap), _p_setp(0), _c_setp(0), _datasem(0), _spacesem(cap)
        {
        }
        void EQueue(const T &in)
        {
            // 生产者
            _spacesem.p();
            {
                LockGurd l(_p_mutex);
                // 生产的工作
                _ring[_p_setp] = in;
                _p_setp++;
                _p_setp %= _cop; // 维持唤醒特性
            }

            _datasem.V();
        }
        void Pop(T *out)
        {
            // 消费者
            _datasem.p();
            {
                LockGurd l(_c_mutex);
                *out = _ring[_c_setp];
                _c_setp++;
                _c_setp %= _cop;
            }

            _spacesem.V();
        }
        ~RingBuffer() {}

    private:
        std::vector<T> _ring; // 环， 临界资源
        int _cop;             // 总容量
        int _p_setp;          // 生产者位置
        int _c_setp;          // 消费位置

        Sem _datasem;  // 数据信号量
        Sem _spacesem; // 空间信号量

        mutex _p_mutex;
        mutex _c_mutex;
    };

}